package com.lineage.server.model;

import com.lineage.config.ConfigAlt;
import com.lineage.config.ConfigOther;
import com.lineage.config.ConfigRate;
import com.lineage.config.Config_Pc_Damage;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.Instance.L1PetInstance;
import com.lineage.server.model.Instance.L1SummonInstance;
import com.lineage.server.model.gametime.L1GameTimeClock;
import com.lineage.server.model.poison.L1DamagePoison;
import com.lineage.server.model.poison.L1ParalysisPoison;
import com.lineage.server.model.poison.L1SilencePoison;
import com.lineage.server.serverpackets.S_AttackPacketNpc;
import com.lineage.server.serverpackets.S_DoActionGFX;
import com.lineage.server.serverpackets.S_ServerMessage;
import com.lineage.server.serverpackets.S_SkillSound;
import com.lineage.server.serverpackets.S_SystemMessage;
import com.lineage.server.serverpackets.S_UseArrowSkill;
import com.lineage.server.serverpackets.S_UseAttackSkill;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.L1ItemSpecialAttributeChar;
import com.lineage.server.timecontroller.server.ServerWarExecutor;
import com.lineage.server.types.Point;
import com.lineage.server.utils.RandomArrayList;
import java.util.Iterator;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class L1AttackNpc extends L1AttackMode {
  private static final Log _log = LogFactory.getLog(L1AttackNpc.class);
  
  L1ItemSpecialAttributeChar item_attr_char = null;
  
  Random random = new Random();
  
  public L1AttackNpc(L1NpcInstance attacker, L1Character target) {
    if (attacker == null)
      return; 
    if (target == null)
      return; 
    if (target.isDead())
      return; 
    if (target.getCurrentHp() <= 0)
      return; 
    this._npc = attacker;
    if (target instanceof L1PcInstance) {
      this._targetPc = (L1PcInstance)target;
      this._calcType = 3;
    } else if (target instanceof L1NpcInstance) {
      this._targetNpc = (L1NpcInstance)target;
      this._calcType = 4;
    } 
    this._target = target;
    this._targetId = target.getId();
    this._targetX = target.getX();
    this._targetY = target.getY();
  }
  
  public boolean calcHit() {
    if (this._target == null)
      return this._isHit = false; 
    switch (this._calcType) {
      case 3:
        this._isHit = calcPcHit();
        break;
      case 4:
        this._isHit = calcNpcHit();
        break;
    } 
    return this._isHit;
  }
  
  private boolean calcPcHit() {
    if (L1AttackMode.dmg0((L1Character)this._targetPc))
      return false; 
    if ((this._npc instanceof L1PetInstance || this._npc instanceof L1SummonInstance) && 
      this._targetPc.getZoneType() == 1)
      return false; 
    if (calcEvasion())
      return false; 
    this._hitRate += this._npc.getLevel() + 5;
    if (this._npc instanceof L1PetInstance)
      this._hitRate += ((L1PetInstance)this._npc).getHitByWeapon(); 
    this._hitRate += this._npc.getHitup();
    int attackerDice = L1AttackMode._random.nextInt(20) + 1 + this._hitRate - 3;
    int tgChaDodgeDown = this._targetPc.get_dodge() * 10;
    if (tgChaDodgeDown > 0)
      attackerDice -= tgChaDodgeDown; 
    int defenderDice = 0;
    int defenderValue = this._targetPc.getAc() * -1;
    if (this._targetPc.getAc() >= 0) {
      defenderDice = 10 - this._targetPc.getAc();
    } else if (this._targetPc.getAc() < 0) {
      defenderDice = 10 + L1AttackMode._random.nextInt(defenderValue) + 1;
    } 
    int fumble = this._hitRate;
    int critical = this._hitRate + 19;
    if (attackerDice <= fumble) {
      this._hitRate = 15;
    } else if (attackerDice >= critical) {
      this._hitRate = 100;
    } else if (attackerDice > defenderDice) {
      this._hitRate = 100;
    } else if (attackerDice <= defenderDice) {
      this._hitRate = 15;
    } 
    if (this._npc.getNpcTemplate().is_boss())
      this._hitRate += Config_Pc_Damage.BossMobHit_chance; 
    if (!this._npc.getNpcTemplate().is_boss())
      this._hitRate += Config_Pc_Damage.AllMobHit_chance; 
    int rnd = L1AttackMode._random.nextInt(100) + 1;
    if (this._npc.get_ranged() >= 10 && this._hitRate > rnd && 
      this._npc.getLocation().getTileLineDistance(new Point(this._targetX, this._targetY)) >= 2)
      return calcErEvasion(); 
    return (this._hitRate >= rnd);
  }
  
  private boolean calcNpcHit() {
    if (L1AttackMode.dmg0((L1Character)this._targetNpc))
      return false; 
    this._hitRate += this._npc.getLevel() + 3;
    if (this._npc instanceof L1PetInstance)
      this._hitRate += ((L1PetInstance)this._npc).getHitByWeapon(); 
    this._hitRate += this._npc.getHitup();
    int attackerDice = L1AttackMode._random.nextInt(20) + 1 + this._hitRate - 3;
    attackerDice += L1AttackMode.attackerDice((L1Character)this._targetNpc);
    if (this._npc.getNpcTemplate().get_nameid().startsWith("BOSS"))
      attackerDice += 30; 
    int defenderDice = 0;
    int defenderValue = this._targetNpc.getAc() * -1;
    if (this._targetNpc.getAc() >= 0) {
      defenderDice = 10 - this._targetNpc.getAc();
    } else if (this._targetNpc.getAc() < 0) {
      defenderDice = 10 + L1AttackMode._random.nextInt(defenderValue) + 1;
    } 
    int fumble = this._hitRate;
    int critical = this._hitRate + 19;
    if (attackerDice <= fumble) {
      this._hitRate = 0;
    } else if (attackerDice >= critical) {
      this._hitRate = 100;
    } else if (attackerDice > defenderDice) {
      this._hitRate = 100;
    } else if (attackerDice <= defenderDice) {
      this._hitRate = 0;
    } 
    int rnd = L1AttackMode._random.nextInt(100) + 1;
    return (this._hitRate >= rnd);
  }
  
  public int calcDamage() {
    switch (this._calcType) {
      case 3:
        this._damage = calcPcDamage();
        break;
      case 4:
        this._damage = calcNpcDamage();
        break;
    } 
    return this._damage;
  }
  
  private double npcDmgMode(double dmg) {
    if (this._npc.getNpcTemplate().get_nameid().startsWith("BOSS"))
      dmg *= 2.0D; 
    if (L1AttackMode._random.nextInt(100) < 15)
      dmg *= 1.8D; 
    dmg += this._npc.getDmgup();
    if (isUndeadDamage())
      dmg *= 1.1D; 
    dmg = (int)(dmg * getLeverage() / 10.0D);
    if (this._npc.isWeaponBreaked())
      dmg /= 2.0D; 
    return dmg;
  }
  
  private int calcPcDamage() {
    if (this._targetPc == null)
      return 0; 
    if (L1AttackMode.dmg0((L1Character)this._targetPc)) {
      this._isHit = false;
      return 0;
    } 
    if (!this._isHit)
      return 0; 
    if (this._targetPc.hasSkillEffect(91)) {
      L1MagicMode magic = new L1MagicPc(this._targetPc, (L1Character)this._npc);
      boolean isProbability = magic.calcProbabilityMagic(91);
      boolean isShortDistance = isShortDistance();
      if (isProbability && isShortDistance) {
        commitCounterBarrier();
        this._npc.broadcastPacketAll((ServerBasePacket)new S_SkillSound(this._targetPc.getId(), 10710));
        return 0;
      } 
    } 
    int lvl = this._npc.getLevel();
    double dmg = 0.0D;
    Integer dmgStr = L1AttackList.STRD.get(Integer.valueOf(this._npc.getStr()));
    if (this._targetPc.getMapId() == 1936) {
      dmg = 30.0D + this._npc.getStr() * 0.8D + dmgStr.intValue();
    } else {
      dmg = L1AttackMode._random.nextInt(lvl)  + dmgStr.intValue();
      dmg = dmg + this._npc.getStr() * ConfigRate.STRRATE / 100.0D;
      dmg = dmg + lvl * (ConfigRate.MONSTERDMG / 100.0D);
    } 
    if (this._npc instanceof L1PetInstance) {
      dmg += (lvl / 7);
      dmg += ((L1PetInstance)this._npc).getDamageByWeapon();
    } 
    dmg = npcDmgMode(dmg);
    dmg -= calcPcDefense();
    dmg -= (this._targetPc.getDamageReductionByArmor() + this._targetPc.getother_ReductionDmg() + 
      this._targetPc.getClan_ReductionDmg() + this._targetPc.get_reduction_dmg() + 
      this._targetPc.getdolldamageReductionByArmor());
    dmg -= this._targetPc.dmgDowe();
    if (this._targetPc.getClanid() != 0)
      dmg -= L1AttackMode.getDamageReductionByClan(this._targetPc); 
    if (this._targetPc.hasSkillEffect(8867))
      dmg = 0.0D; 
    if (Config_Pc_Damage.ModDmg > 0.0D)
      dmg *= Config_Pc_Damage.ModDmg; 
    if (this._npc.getNpcTemplate().is_boss() && Config_Pc_Damage.BossDmg > 0.0D)
      dmg *= Config_Pc_Damage.BossDmg; 
    if (this._targetPc.getNoweaponRedmg() > 0)
      dmg -= this._targetPc.getNoweaponRedmg(); 
    if (this._targetPc.isIllusionist() && this._targetPc.getlogpcpower_SkillFor4() != 0) {
      int hp = this._targetPc.getMaxHp() / this._targetPc.getCurrentHp();
      if (hp > 1) {
        if (hp > 10)
          hp = 10; 
        if (RandomArrayList.getInc(100, 1) <= this._targetPc.getlogpcpower_SkillFor4()) {
          dmg -= (hp * 40);
          this._targetPc.sendPackets((ServerBasePacket)new S_SystemMessage("触发 痛苦化身 减免了" + (hp * 40) + "滴伤害。"));
          this._targetPc.sendPackets((ServerBasePacket)new S_SkillSound(this._targetPc.getId(), 5377));
        } 
      } 
    } 
    if (this._targetPc.hasSkillEffect(168) && this._targetPc.isElf() && 
      this._targetPc.getlogpcpower_SkillFor3() != 0 && this._targetPc.getElfAttr() == 1 && 
      RandomArrayList.getInc(100, 1) <= this._targetPc.getlogpcpower_SkillFor3()) {
      dmg *= 0.3D;
      this._targetPc.sendPackets((ServerBasePacket)new S_SkillSound(this._targetPc.getId(), 5377));
      this._targetPc.sendPackets((ServerBasePacket)new S_SystemMessage("触发 精通能量 减免伤害"));
    } 
    if (this._targetPc.isDragonKnight() && this._targetPc.getlogpcpower_SkillFor3() != 0 && 
      RandomArrayList.getInc(100, 1) <= this._targetPc.getlogpcpower_SkillFor3()) {
      dmg -= (int)dmg * this._targetPc.getlogpcpower_SkillFor3() * 0.01D;
      this._targetPc.sendPackets((ServerBasePacket)new S_SystemMessage("触发 强之护铠"));
    } 
    int ran = L1AttackMode._random.nextInt(100) + 1;
    if (this._targetPc.getInventory().checkSkillType(113) && ran <= ConfigOther.armor_type1)
      dmg *= 0.98D; 
    if (this._targetPc.getInventory().checkSkillType(114) && ran <= ConfigOther.armor_type2)
      dmg *= 0.95D; 
    if (this._targetPc.getInventory().checkSkillType(115) && ran <= ConfigOther.armor_type3)
      dmg *= 0.9D; 
    if (this._targetPc.getInventory().checkSkillType(116) && ran <= ConfigOther.armor_type4)
      dmg *= 0.85D; 
    if (this._targetPc.getInventory().checkSkillType(117) && ran <= ConfigOther.armor_type5)
      dmg *= 0.8D; 
    if (this._targetPc.getInventory().checkSkillType(128) && ran <= ConfigOther.armor_type16)
      dmg = 0.0D; 
    if (this._targetPc.getInventory().checkSkillType(129) && ran <= ConfigOther.armor_type17)
      dmg = 0.0D; 
    if (this._targetPc.getInventory().checkSkillType(130) && ran <= ConfigOther.armor_type18)
      dmg = 0.0D; 
    if (this._targetPc.getInventory().checkSkillType(131) && ran <= ConfigOther.armor_type19)
      dmg = 0.0D; 
    if (this._targetPc.getInventory().checkSkillType(132) && ran <= ConfigOther.armor_type20)
      dmg = 0.0D; 
    if (this._targetPc.hasSkillEffect(219))
      dmg -= dmg * (this._targetPc.getAvatar() / 100); 
    Iterator<L1ItemInstance> iterator = this._targetPc.getInventory().getItems().iterator();
    while (iterator.hasNext()) {
      L1ItemInstance item = iterator.next();
      if (item.getItemId() == 400041 && item.isEquipped()) {
        Random random = new Random();
        int r = random.nextInt(100) + 1;
        if (item.getEnchantLevel() * 2 < r)
          continue; 
        dmg -= 50.0D;
        this._targetPc.sendPacketsAll((ServerBasePacket)new S_SkillSound(this._targetPc.getId(), 6320));
      } 
    } 
    if (this._targetPc.hasSkillEffect(68))
      dmg /= ConfigOther.IMMUNE_TO_HARM_NPC; 
    boolean isNowWar = false;
    int castleId = L1CastleLocation.getCastleIdByArea((L1Character)this._npc);
    if (castleId > 0)
      isNowWar = ServerWarExecutor.get().isNowWar(castleId); 
    if (!isNowWar) {
      if (this._npc instanceof L1PetInstance)
        dmg *= ConfigOther.petdmgotherpc; 
      if (this._npc instanceof L1SummonInstance) {
        L1SummonInstance summon = (L1SummonInstance)this._npc;
        if (summon.isExsistMaster())
          dmg *= ConfigOther.summondmgotherpc; 
      } 
    } else if (isNowWar) {
      if (this._npc instanceof L1PetInstance)
        dmg *= ConfigOther.petdmgotherpc_war; 
      if (this._npc instanceof L1SummonInstance) {
        L1SummonInstance summon = (L1SummonInstance)this._npc;
        if (summon.isExsistMaster())
          dmg *= ConfigOther.summondmgotherpc_war; 
      } 
    } 
    if (dmg <= 0.0D)
      this._isHit = false; 
    addNpcPoisonAttack((L1Character)this._targetPc);
    if (!this._isHit)
      dmg = 0.0D; 
    return (int)dmg;
  }
  
  private int calcNpcDamage() {
    if (this._targetNpc == null)
      return 0; 
    if (L1AttackMode.dmg0((L1Character)this._targetNpc)) {
      this._isHit = false;
      return 0;
    } 
    int lvl = this._npc.getLevel();
    double dmg = 0.0D;
    if (this._npc instanceof L1PetInstance) {
      dmg = (L1AttackMode._random.nextInt(this._npc.getNpcTemplate().get_level()) + this._npc.getStr() / 2 + 1);
      dmg += (lvl / 14);
      dmg += ((L1PetInstance)this._npc).getDamageByWeapon();
      if (ConfigOther.petdmgother > 0.0D)
        dmg *= ConfigOther.petdmgother; 
    } else if (this._npc instanceof L1SummonInstance) {
      Integer dmgStr = L1AttackList.STRD.get(Integer.valueOf(this._npc.getStr()));
      dmg = (L1AttackMode._random.nextInt(lvl) + this._npc.getStr() / 2 + dmgStr.intValue());
      if (ConfigOther.summondmgother > 0.0D)
        dmg *= ConfigOther.summondmgother; 
    } else {
      Integer dmgStr = L1AttackList.STRD.get(Integer.valueOf(this._npc.getStr()));
      dmg = (L1AttackMode._random.nextInt(lvl) + this._npc.getStr() / 2 + dmgStr.intValue());
    } 
    dmg = npcDmgMode(dmg);
    dmg -= calcNpcDamageReduction();
    addNpcPoisonAttack((L1Character)this._targetNpc);
    if (this._targetNpc.hasSkillEffect(68))
      dmg /= 2.0D; 
    if (dmg <= 0.0D)
      this._isHit = false; 
    if (!this._isHit)
      dmg = 0.0D; 
    return (int)dmg;
  }
  
  private boolean isUndeadDamage() {
    boolean flag = false;
    int undead = this._npc.getNpcTemplate().get_undead();
    boolean isNight = L1GameTimeClock.getInstance().currentTime().isNight();
    if (isNight)
      switch (undead) {
        case 1:
        case 3:
        case 4:
          flag = true;
          break;
      }  
    return flag;
  }
  
  private void addNpcPoisonAttack(L1Character target) {
    switch (this._npc.getNpcTemplate().get_poisonatk()) {
      case 1:
        if (15 >= L1AttackMode._random.nextInt(100) + 1)
          L1DamagePoison.doInfection((L1Character)this._npc, target, 3000, 20); 
        break;
      case 2:
        if (15 >= L1AttackMode._random.nextInt(100) + 1)
          L1SilencePoison.doInfection(target); 
        break;
      case 4:
        if (15 >= L1AttackMode._random.nextInt(100) + 1)
          L1ParalysisPoison.doInfection(target, 20000, 45000); 
        break;
    } 
  }
  
  public void action() {
    try {
      if (this._npc == null)
        return; 
      if (this._npc.isDead())
        return; 
      this._npc.setHeading(this._npc.targetDirection(this._targetX, this._targetY));
      boolean isLongRange = (this._npc.getLocation()
        .getTileLineDistance(new Point(this._targetX, this._targetY)) > 1);
      int bowActId = this._npc.getBowActId();
      if (isLongRange && bowActId > 0) {
        actionX1();
      } else {
        actionX2();
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private void actionX1() {
    try {
      int bowActId = this._npc.getBowActId();
      int actId = 1;
      if (getActId() > 1)
        actId = getActId(); 
      if (this._isHit) {
        this._npc.broadcastPacketAll((ServerBasePacket)new S_UseArrowSkill((L1Character)this._npc, this._targetId, bowActId, this._targetX, 
              this._targetY, this._damage, actId));
      } else {
        this._npc.broadcastPacketAll(
            (ServerBasePacket)new S_UseArrowSkill((L1Character)this._npc, bowActId, this._targetX, this._targetY, actId));
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private void actionX2() {
    try {
      int actId = 1;
      if (getActId() > 1)
        actId = getActId(); 
      switch (this._npc.getTempCharGfx()) {
        case 1780:
        case 7430:
        case 13076:
          actId = 30;
          break;
        case 2757:
        case 4104:
        case 13096:
          actId = 18;
          break;
      } 
      if (this._isHit) {
        if (getGfxId() > 0) {
          this._npc.broadcastPacketAll((ServerBasePacket)new S_UseAttackSkill((L1Character)this._npc, this._target.getId(), getGfxId(), 
                this._targetX, this._targetY, actId, this._damage));
        } else {
          gfx7049();
          this._npc.broadcastPacketAll((ServerBasePacket)new S_AttackPacketNpc(this._npc, this._target, actId, this._damage));
        } 
      } else if (getGfxId() > 0) {
        this._npc.broadcastPacketAll((ServerBasePacket)new S_UseAttackSkill(this._target, this._npc.getId(), getGfxId(), 
              this._targetX, this._targetY, actId, 0));
      } else {
        this._npc.broadcastPacketAll((ServerBasePacket)new S_AttackPacketNpc(this._npc, this._target, actId));
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private void gfx7049() {
    if (this._npc.getStatus() != 58)
      return; 
    boolean is = false;
    if (this._npc.getTempCharGfx() == 6671)
      is = true; 
    if (this._npc.getTempCharGfx() == 6650)
      is = true; 
    if (is)
      this._npc.broadcastPacketAll((ServerBasePacket)new S_SkillSound(this._npc.getId(), 7049)); 
  }
  
  public void commit() {
    if (this._isHit)
      switch (this._calcType) {
        case 3:
          commitPc();
          break;
        case 4:
          commitNpc();
          break;
      }  
    if (!ConfigAlt.ALT_ATKMSG)
      return; 
    if (this._calcType == 4)
      return; 
    if (!this._targetPc.isGm())
      return; 
    String srcatk = this._npc.getName();
    String tgatk = this._targetPc.getName();
    String dmginfo = this._isHit ? ("伤害:" + this._damage) : "失败";
    String hitinfo = " 命中:" + this._hitRate + "% 剩余hp:" + this._targetPc.getCurrentHp();
    String x = String.valueOf(String.valueOf(srcatk)) + ">" + tgatk + " " + dmginfo + hitinfo;
    this._targetPc.sendPackets((ServerBasePacket)new S_ServerMessage(166, "受到NPC攻击: " + x));
  }
  
  private void commitPc() {
    this._targetPc.receiveDamage((L1Character)this._npc, this._damage, false, false);
  }
  
  private void commitNpc() {
    this._targetNpc.receiveDamage((L1Character)this._npc, this._damage);
  }
  
  public boolean isShortDistance() {
    boolean isShortDistance = true;
    boolean isLongRange = (this._npc.getLocation()
      .getTileLineDistance(new Point(this._targetX, this._targetY)) > 1);
    int bowActId = this._npc.getBowActId();
    if (isLongRange && bowActId > 0)
      isShortDistance = false; 
    return isShortDistance;
  }
  
  public void commitCounterBarrier() {
    int damage = calcCounterBarrierDamage();
    if (damage == 0)
      return; 
    if (this._npc.hasSkillEffect(68))
      damage /= 2; 
    this._npc.receiveDamage(this._target, damage);
    this._npc.broadcastPacketAll((ServerBasePacket)new S_DoActionGFX(this._npc.getId(), 2));
    this._npc.broadcastPacketAll((ServerBasePacket)new S_SkillSound(this._target.getId(), 10710));
  }
  
  public void calcStaffOfMana() {}
}
